package utils

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"os"
	"ssadmin/common/constant"
	"strconv"
	"time"
)

var (
	aesKey = []byte("aes1584407805313")
)

// 返回一个32位md5加密后的字符串
func Md5Pwd(pwd, full string) string {
	b := []byte(pwd)
	s := []byte(full)
	h := md5.New()
	h.Write(s)
	h.Write(b)
	var res []byte
	res = h.Sum(nil)
	for i := 0; i < 2-1; i++ {
		h.Reset()
		h.Write(res)
		res = h.Sum(nil)
	}
	return hex.EncodeToString(res)
}
func Md5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}
func Md5To16(str string) string {
	return Md5(str)[8:24]
}
func GetUUIdTo16() string {
	//获取当前时间戳
	nowTime := time.Now().Unix()
	//字符串md5加密
	return Md5To16(strconv.FormatInt(nowTime, 10))
}

func AesEncrypt(origData, key string) (string, error) {
	if len(key) == 0 {
		key = "aes1584407805313"
	}
	aesKey := []byte(key)
	val := []byte(origData)
	block, err := aes.NewCipher(aesKey)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	val = PKCS7Padding(val, blockSize)
	blockMode := cipher.NewCBCEncrypter(block, aesKey[:blockSize])
	crypted := make([]byte, len(val))
	blockMode.CryptBlocks(crypted, val)

	//byte数组转换字符串
	res := base64.StdEncoding.EncodeToString(crypted)
	return res, nil
}

// AES解密
func AesDecrypt(crypted, key string) (string, error) {
	if len(key) == 0 {
		key = "aes1584407805313"
	}
	aesKey := []byte(key)

	//字符串转换成byte数组
	val, _ := base64.StdEncoding.DecodeString(crypted)
	block, err := aes.NewCipher(aesKey)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	blockMode := cipher.NewCBCDecrypter(block, aesKey[:blockSize])
	origData := make([]byte, len(val))
	blockMode.CryptBlocks(origData, val)
	origData = PKCS7UnPadding(origData)

	//剔除空白字符
	res := []byte{}
	for i := range origData {
		val := origData[i]
		if val != 0 {
			res = append(res, val)
		}
	}
	return string(res), nil
}

func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func PKCS7UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func NewUserDefaultPwd(username string, password ...string) (pwd string) {
	str := constant.DefaultPwd

	if len(password) != 0 {
		str = password[0]
	}
	return Md5Pwd(str, username+str)
}

func RsaEncrypt(plainText string) (string, error) {
	file, _ := os.Open("public.pem")
	defer file.Close()
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	_, _ = file.Read(buf)
	block, _ := pem.Decode(buf)
	publicInterface, _ := x509.ParsePKIXPublicKey(block.Bytes)
	pubKey, flag := publicInterface.(*rsa.PublicKey)
	if flag == false {
		return "", errors.New("RSA加密失败")
	}
	cipherBytes, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, []byte(plainText))
	if err != nil {
		return "", errors.New("RSA加密失败")
	}
	cipherText := hex.EncodeToString(cipherBytes)
	return cipherText, nil
}

func RsaDecrypt(cipherText string) (plainText string, err error) {
	decodeBytes, err := hex.DecodeString(cipherText)
	file, _ := os.Open("private.pem")
	defer file.Close()
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	_, _ = file.Read(buf)
	block, _ := pem.Decode(buf)
	priKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
	plainBytes, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, decodeBytes)
	if err != nil {
		return "", errors.New("RSA解密失败")
	}
	return string(plainBytes), err
}

func CustRsaEncrypt(publicKey, originData string) (string, error) {
	if len(publicKey) == 0 || len(originData) == 0 {
		return "", errors.New("参数异常")
	}
	block, _ := pem.Decode([]byte(publicKey))
	if block == nil {
		return "", errors.New("加解密失败")
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return "", err
	}
	pub := pubInterface.(*rsa.PublicKey)
	paramEncrypt, err := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(originData))
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(paramEncrypt), nil
}
